home *** CD-ROM | disk | FTP | other *** search
/ PCMania 43 / PCMania CD43_1.nrg / midi / midi2txt.cpp < prev    next >
C/C++ Source or Header  |  1995-06-05  |  15KB  |  764 lines

  1. #include "midiio.hpp"
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4. #include <string.h>
  5. #include <dos.h>
  6.  
  7. // info = -1 is lyric!
  8.  
  9. class MidiPrint : public MidiRead
  10. {
  11. public:
  12.   MidiPrint(char* name);
  13.  
  14.   virtual void head(unsigned songs, unsigned tracks, unsigned clicksperquarter);
  15.   virtual void track(int trackno, unsigned length, int channel);
  16.   virtual void endtrack(int trackno);
  17.  
  18.   virtual void seqnumber(unsigned int seqno);
  19.   virtual void text(int what, int len, char* whattext, unsigned char* txt);
  20.   virtual void meta(int what, int len, unsigned char* data);
  21.   virtual void end();
  22.   virtual void smpteofs(int hour, int min, int sec, int frame, int fracframe);
  23.   virtual void tact(int nom, int denom, int clicksperbeat, int notes32perbeat);
  24.   virtual void tempo(unsigned long ticks);
  25.   virtual void key(int signature, int isminor);
  26.  
  27.   virtual void program(int prg, int channel);
  28.   virtual void control(int channel, int what, int value);
  29.   virtual void highbank(int channel, int val);
  30.   virtual void wheel(int channel, int val);
  31.   virtual void breath(int channel, int val);
  32.   virtual void foot(int channel, int val);
  33.   virtual void portamentotime(int channel, int val);
  34.   virtual void data(int channel, int val);
  35.   virtual void volume(int channel, int val);
  36.   virtual void balance(int channel, int val);
  37.   virtual void expression(int channel, int val);
  38.   virtual void lowbank(int channel, int val);
  39.   virtual void hold(int channel, int val);
  40.   virtual void reverb(int channel, int val);
  41.   virtual void chorus(int channel, int val);
  42.   virtual void datainc(int channel, int val);
  43.   virtual void datadec(int channel, int val);
  44.   virtual void noteon(int channel, int note, int vel);
  45.   virtual void noteoff(int channel, int note, int vel);
  46.   virtual void time(unsigned long ticks);
  47.   virtual void pitchbend(int channel, int val);
  48.   virtual void polyaftertouch(int channel, int note, int val);
  49.   virtual void aftertouch(int channel, int val);
  50.   virtual void songpos(unsigned pos);
  51.   virtual void songselect(unsigned char song);
  52.   virtual void tunerequest();
  53.   virtual void timingclock();
  54.   virtual void start();
  55.   virtual void cont();
  56.   virtual void stop();
  57.   virtual void activesense();
  58.   virtual void sysex(int syslen, unsigned char* sysdata);
  59.   virtual void endmidi();
  60.   virtual void error(const char* msg);
  61.  
  62.   virtual void percent(int perc);
  63.  
  64.   void printchannel(int channel);
  65.  
  66.   int info_;
  67.   int marktact_;
  68.  
  69. private:
  70.   int indent_;
  71.   unsigned tactunits_;
  72.   unsigned quarterunits_;
  73.   unsigned long curtime_;
  74.  
  75.   int nl_;
  76.  
  77.   void indent();
  78. };
  79.  
  80. MidiPrint::MidiPrint(char* name) : MidiRead(name)
  81. {
  82.   indent_ = 0;
  83.   info_ = 3;
  84.   marktact_ = 0;
  85.   tactunits_ = 0;
  86.   nl_ = 1;
  87. }
  88.  
  89. void MidiPrint::indent()
  90. {
  91.   for (; indent_ > 0; indent_--)
  92.     putchar(' ');
  93. }
  94.  
  95. void MidiPrint::head(unsigned songs, unsigned tracks, unsigned clicksperquarter)
  96. {
  97.   quarterunits_ = clicksperquarter;
  98.   if (midiname_)
  99.     printf("// %s\n", midiname_);
  100.   if (info_ == 1 || info_ == -1)
  101.     return;
  102.   printf("mthd\n");
  103.   printf("  // %d song%s\n", songs, songs != 1 ? "s" : "");
  104.   printf("  // %d track%s\n", tracks, tracks != 1 ? "s" : "");
  105.   printf("  unit %d // is 1/4\n", clicksperquarter);
  106.   printf("end mthd\n");
  107. }
  108.  
  109. void MidiPrint::track(int trackno, unsigned length, int channel)
  110. {
  111.   curtime_ = 0;
  112.   if (info_ == 1 || info_ == -1)
  113.     return;
  114.   printf("\nmtrk");
  115.   if (channel >= 0)
  116.     printf("($%X)\n", channel+1);
  117.   else if (channel == MULTICHANNEL)
  118.     printf(" // multichannel track\n");
  119.   else
  120.     printf("\n");
  121. }
  122.  
  123. void MidiPrint::endtrack(int trackno)
  124. {
  125.   if (info_ == 1)
  126.     return;
  127.   if (info_ == -1)
  128.   {
  129.     if (!nl_)
  130.     {
  131.       nl_ = 1;
  132.       printf("\n");
  133.     }
  134.     return;
  135.   }
  136.   printf("end mtrk\n");
  137. }
  138.  
  139. void printchar(int c)
  140. {
  141.   if (c < 0)
  142.     return;
  143.   if (c == '\\')
  144.     printf("\\\\");
  145.   else if (c == '"')
  146.     printf("\\\"");
  147.   else if (c != 0 && (isprint(c) || strchr("äöüÄÖÜß", c) != 0))
  148.     putchar(c);
  149.   else
  150.     printf("\\x%02x", c);
  151. }
  152.  
  153. void MidiPrint::seqnumber(unsigned int seqno)
  154. {
  155.   indent();
  156.   printf("seqnumber %u\n", seqno);
  157. }
  158.  
  159. void MidiPrint::text(int what, int len, char* whattext, unsigned char* txt)
  160. {
  161.   if (info_ == -1 && txt)
  162.   {
  163.     if (what == meta_lyric || what == meta_text)
  164.     {
  165.     char* bs;
  166.  
  167.       while ((bs = (char*)memchr(txt, '\\', len)) != 0)
  168.     *bs = '\n';
  169.       while ((bs = (char*)memchr(txt, '/', len)) != 0)
  170.     *bs = '\n';
  171.       if (*txt == '@')
  172.       {
  173.     txt++; len--;
  174.     switch(*txt)
  175.     {
  176.     case 'K': printf("\nKind: "); break;
  177.     case 'V': printf("\nVersion: "); break;
  178.     case 'I': printf("\nInformation: "); break;
  179.     case 'T': printf("\nTitle: "); break;
  180.     case 'L': printf("\nLanguage: "); break;
  181.     default:  printf("\n@%c: ", *txt); break;
  182.     }
  183.     if (*txt)
  184.     {
  185.       txt++;
  186.       len--;
  187.     }
  188.       }
  189.       nl_ = txt[len-1] == '\n';
  190.       printf("%.*s", len, txt);
  191.     }
  192.     return;
  193.   }
  194.   indent();
  195.   if (whattext)
  196.     printf("%s ", whattext);
  197.   else
  198.     printf("metaevent %d(%d) ", what, len);
  199.  
  200.   putchar('"');
  201.   if (txt)
  202.   {
  203.     while (len-- > 0)
  204.       printchar(*txt++);
  205.   }
  206.   putchar('"');
  207.   if (!whattext)
  208.     printf(" end metaevent");
  209.   printf("\n");
  210. }
  211.  
  212. void MidiPrint::meta(int what, int len, unsigned char* data)
  213. {
  214. int i;
  215.  
  216.   if (info_ < 3)
  217.     return;
  218.   indent();
  219.   printf("metaevent %d(%d)", what, len);
  220.   i = 0;
  221.   while (len-- > 0)
  222.   {
  223.     indent_ = 4;
  224.     printf(" $%02X", *data++);
  225.     if ( (i % 16) == 15)
  226.     {
  227.       printf("\n");
  228.       indent();
  229.     }
  230.     i++;
  231.   }
  232.   printf(" end metaevent\n");
  233. }
  234.  
  235. void MidiPrint::end()
  236. {
  237. }
  238.  
  239. void MidiPrint::smpteofs(int hour, int min, int sec, int frame, int fracframe)
  240. {
  241.   if (info_ < 3)
  242.     return;
  243.   printf("smpteofs %02d:%02d:%02d:%d:%d\n",
  244.     hour, min, sec, frame, fracframe);
  245. }
  246.  
  247. void MidiPrint::tact(int nom, int denom, int clicksperbeat, int notes32perbeat)
  248. {
  249.   if (info_ < 1)
  250.     return;
  251.   indent();
  252.   printf("tact %d / %d %d %d\n", nom, denom, clicksperbeat, notes32perbeat);
  253.   if (!marktact_)
  254.     return;
  255.   if (tactunits_)
  256.   {
  257.     tactunits_ = 0;
  258.     marktact_ = 0;
  259.   }
  260.   else
  261.     tactunits_ = quarterunits_ * 4 * nom / denom;
  262. }
  263.  
  264. void MidiPrint::tempo(unsigned long ticks)
  265. {
  266.   if (info_ < 1)
  267.     return;
  268.   indent();
  269.   if (ticks != 0)
  270.   {
  271.   unsigned long beat = 60000000l / ticks;
  272.  
  273.     if (beat * ticks == 60000000l)
  274.     {
  275.       printf("beats %ld\n", beat);
  276.       return;
  277.     }
  278.   }
  279.  
  280.   printf("tempo %ld", ticks);
  281.   if (ticks != 0)
  282.     printf(" // about %ld beats/min", 60000000l / ticks);
  283.   printf("\n");
  284. }
  285.  
  286. void MidiPrint::key(int signature, int isminor)
  287. {
  288.   if (info_ < 3)
  289.     return;
  290.   indent();
  291.   printf("key \"");
  292.   if (signature != 0)
  293.   {
  294.     printf("%d%c ", (signature < 0) ? -signature : signature,
  295.     (signature < 0) ? 'b' : '#');
  296.   }
  297.   else
  298.     printf("C");
  299.   printf("%s\"\n",  isminor ? "min" : "maj");
  300. }
  301.  
  302. void MidiPrint::printchannel(int channel)
  303. {
  304.   if (info_ < 3)
  305.     return;
  306.   if (getchannel() != channel)
  307.   {
  308.     indent();
  309.     if (channel >= 10)
  310.       printf("[$%X]", channel+1);
  311.     else if (channel >= 0)
  312.       printf("[%d]", channel+1);
  313.     setchannel(channel);
  314.   }
  315. }
  316.  
  317. void MidiPrint::time(unsigned long ticks)
  318. {
  319. unsigned long n;
  320.  
  321.   indent_ = 2;
  322.   while (ticks > 0)
  323.   {
  324.     if (!marktact_ || !tactunits_)
  325.       n = ticks;
  326.     else
  327.     {
  328.       if (curtime_ % tactunits_ == 0)
  329.     n = tactunits_;
  330.       else
  331.     n = tactunits_ - curtime_ % tactunits_;
  332.       if (n > ticks)
  333.     n = ticks;
  334.     }
  335.     if (info_ < 3)
  336.       return;
  337.     if (n > 0)
  338.     {
  339.       indent();
  340.       curtime_ += n;
  341.       if ((n % quarterunits_) == 0)
  342.     printf("%d/4", n / quarterunits_);
  343.       else if (quarterunits_ % 2 == 0 && (n % (quarterunits_ / 2)) == 0)
  344.     printf("%d/8", n / (quarterunits_/2));
  345.       else if (quarterunits_ % 4 == 0 && (n % (quarterunits_ / 4)) == 0)
  346.     printf("%d/16", n / (quarterunits_/4));
  347.       else
  348.     printf("%ld", n);
  349.       if (!marktact_ || !tactunits_ || (curtime_ % tactunits_) != 0)
  350.     putchar(';');
  351.       else
  352.       {
  353.     printf(". // tact %lu\n", curtime_ / tactunits_);
  354.     indent_ = 2;
  355.       }
  356.       ticks -= n;
  357.     }
  358.   }
  359. }
  360.  
  361. void MidiPrint::program(int channel, int prg)
  362. {
  363.   if (info_ < 1)
  364.     return;
  365.   indent();
  366.   printchannel(channel);
  367.   printf("program %s\n", progname(prg, channel));
  368. }
  369.  
  370. void MidiPrint::control(int channel, int what, int value)
  371. {
  372.   if (info_ < 3)
  373.     return;
  374.   indent();
  375.   printchannel(channel);
  376.   printf("control $%02X %d\n", what, value);
  377. }
  378.  
  379. void MidiPrint::balance(int channel, int val)
  380. {
  381.   if (info_ < 3)
  382.     return;
  383.   indent();
  384.   printchannel(channel);
  385.   printf("balance ");
  386.   if (val == 0)
  387.     printf(" left\n");
  388.   else if (val == 127)
  389.     printf(" right\n");
  390.   else
  391.     printf(" %d\n", val);
  392. }
  393.  
  394. void MidiPrint::highbank(int channel, int val)
  395. {
  396.   if (info_ < 2)
  397.     return;
  398.   indent();
  399.   printchannel(channel);
  400.   printf("hbank $%02X\n", val);
  401. }
  402.  
  403. void MidiPrint::wheel(int channel, int val)
  404. {
  405.   if (info_ < 3)
  406.     return;
  407.   indent();
  408.   printchannel(channel);
  409.   printf("wheel %d\n", val);
  410. }
  411.  
  412. void MidiPrint::breath(int channel, int val)
  413. {
  414.   if (info_ < 3)
  415.     return;
  416.   indent();
  417.   printchannel(channel);
  418.   printf("breath %d\n", val);
  419. }
  420.  
  421. void MidiPrint::foot(int channel, int val)
  422. {
  423.   if (info_ < 3)
  424.     return;
  425.   indent();
  426.   printchannel(channel);
  427.   printf("foot %d\n", val);
  428. }
  429.  
  430. void MidiPrint::portamentotime(int channel, int val)
  431. {
  432.   if (info_ < 3)
  433.     return;
  434.   indent();
  435.   printchannel(channel);
  436.   printf("portamentotime %d\n", val);
  437. }
  438.  
  439. void MidiPrint::data(int channel, int val)
  440. {
  441.   if (info_ < 3)
  442.     return;
  443.   indent();
  444.   printchannel(channel);
  445.   printf("data %d\n", val);
  446. }
  447.  
  448. void MidiPrint::volume(int channel, int val)
  449. {
  450.   if (info_ < 2)
  451.     return;
  452.   indent();
  453.   printchannel(channel);
  454.   printf("volume %d\n", val);
  455. }
  456.  
  457. void MidiPrint::expression(int channel, int val)
  458. {
  459.   if (info_ < 3)
  460.     return;
  461.   indent();
  462.   printchannel(channel);
  463.   printf("expression %d\n", val);
  464. }
  465.  
  466. void MidiPrint::lowbank(int channel, int val)
  467. {
  468.   if (info_ < 2)
  469.     return;
  470.   indent();
  471.   printchannel(channel);
  472.   printf("lbank $%02X\n", val);
  473. }
  474.  
  475. void MidiPrint::hold(int channel, int val)
  476. {
  477.   if (info_ < 3)
  478.     return;
  479.   indent();
  480.   printchannel(channel);
  481.   printf("hold ");
  482.   if (val == 0)
  483.     printf(" off\n");
  484.   else if (val == 0x7f)
  485.     printf(" on\n");
  486.   else
  487.     printf(" %d\n", val);
  488. }
  489.  
  490. void MidiPrint::reverb(int channel, int val)
  491. {
  492.   if (info_ < 3)
  493.     return;
  494.   indent();
  495.   printchannel(channel);
  496.   printf("reverb %d\n", val);
  497. }
  498.  
  499. void MidiPrint::chorus(int channel, int val)
  500. {
  501.   if (info_ < 3)
  502.     return;
  503.   indent();
  504.   printchannel(channel);
  505.   printf("chorus %d\n", val);
  506. }
  507.  
  508. void MidiPrint::datainc(int channel, int val)
  509. {
  510.   if (info_ < 3)
  511.     return;
  512.   indent();
  513.   printchannel(channel);
  514.   printf("datainc %d\n", val);
  515. }
  516.  
  517. void MidiPrint::datadec(int channel, int val)
  518. {
  519.   if (info_ < 3)
  520.     return;
  521.   indent();
  522.   printchannel(channel);
  523.   printf("datadec %d\n", val);
  524. }
  525.  
  526. void MidiPrint::noteon(int channel, int note, int vel)
  527. {
  528.   if (info_ < 3)
  529.     return;
  530.   indent();
  531.   printchannel(channel);
  532.   printf("+%s $%02X;\n", notename(note), vel);
  533. }
  534.  
  535. void MidiPrint::noteoff(int channel, int note, int vel)
  536. {
  537.   if (info_ < 3)
  538.     return;
  539.   indent();
  540.   printchannel(channel);
  541.   printf("-%s $%02X;\n", notename(note), vel);
  542. }
  543.  
  544. void MidiPrint::pitchbend(int channel, int val)
  545. {
  546.   if (info_ < 3)
  547.     return;
  548.   indent();
  549.   printchannel(channel);
  550.   printf("pitchbend %d\n", val);
  551. }
  552.  
  553. void MidiPrint::polyaftertouch(int channel, int note, int val)
  554. {
  555.   if (info_ < 3)
  556.     return;
  557.   indent();
  558.   printchannel(channel);
  559.   printf("polyaftertouch %s %d\n", notename(note), val);
  560. }
  561.  
  562. void MidiPrint::aftertouch(int channel, int val)
  563. {
  564.   if (info_ < 3)
  565.     return;
  566.   indent();
  567.   printchannel(channel);
  568.   printf("aftertouch %d\n", val);
  569. }
  570.  
  571. void MidiPrint::songpos(unsigned pos)
  572. {
  573.   if (info_ < 1)
  574.     return;
  575.   indent();
  576.   printf("songpos %d\n", pos);
  577. }
  578.  
  579. void MidiPrint::songselect(unsigned char song)
  580. {
  581.   if (info_ < 1)
  582.     return;
  583.   indent();
  584.   printf("songselect %d\n", song);
  585. }
  586.  
  587. void MidiPrint::tunerequest()
  588. {
  589.   if (info_ < 3)
  590.     return;
  591.   indent();
  592.   printf("tunerequest\n");
  593. }
  594.  
  595. void MidiPrint::timingclock()
  596. {
  597.   if (info_ < 3)
  598.     return;
  599.   indent();
  600.   printf("timingclock\n");
  601. }
  602.  
  603. void MidiPrint::start()
  604. {
  605.   if (info_ < 1)
  606.     return;
  607.   indent();
  608.   printf("start\n");
  609. }
  610.  
  611. void MidiPrint::cont()
  612. {
  613.   if (info_ < 1)
  614.     return;
  615.   indent();
  616.   printf("continue\n");
  617. }
  618.  
  619. void MidiPrint::stop()
  620. {
  621.   if (info_ < 1)
  622.     return;
  623.   indent();
  624.   printf("stop\n");
  625. }
  626.  
  627. void MidiPrint::activesense()
  628. {
  629.   if (info_ < 3)
  630.     return;
  631.   indent();
  632.   printf("activesensing\n");
  633. }
  634.  
  635. void MidiPrint::sysex(int syslen, unsigned char* sysdata)
  636. {
  637. int i = 0;
  638.  
  639.   if (info_ < 3)
  640.     return;
  641.   indent();
  642.   syslen--; // last byte is end of sysex (F7)
  643.   printf("sysevent(%d) ", syslen);
  644.   while (syslen-- > 0)
  645.   {
  646.     indent_ = 4;
  647.     printf("$%02X ", *sysdata++);
  648.     if ( (i % 16) == 15)
  649.     {
  650.       printf("\n");
  651.       indent();
  652.     }
  653.     i++;
  654.   }
  655.   printf("end sysevent\n");
  656. }
  657.  
  658. void MidiPrint::endmidi()
  659. {
  660.   if (info_ < 3)
  661.     return;
  662.   if (getpos() < filesize_)
  663.   {
  664.   long len = filesize_ - getpos();
  665.  
  666.     fprintf(stderr, "garbage at end of midi\n");
  667.     while (len > 0)
  668.     {
  669.     int n = 16;
  670.  
  671.       if (len < n)
  672.     n = (int)len;
  673.       unsigned char* c = get(n);
  674.       if (!c)
  675.     return;
  676.       printf("//");
  677.       for (int i = 0; i < n; i++)
  678.     printf(" %02X", c[i]);
  679.       printf("\n");
  680.       len -= n;
  681.     }
  682.   }
  683. }
  684.  
  685. void MidiPrint::percent(int perc)
  686. {
  687.   if (info_ >= 0)
  688.   fprintf(stderr, "%-3d%%\r", perc);
  689. }
  690.  
  691. void MidiPrint::error(const char* msg)
  692. {
  693.   printf("// error: %s\n", msg);
  694. }
  695.  
  696. void usage()
  697. {
  698.   fprintf(stderr, "usage: midi2txt [-chunk][-short][-info][-lyric][-tact] file.mid [> file.txt]\n");
  699.   exit(1);
  700. }
  701.  
  702. void main(int argc, char**argv)
  703. {
  704. int info = 3;
  705. int tact = 0;
  706.  
  707.   setcbrk(1);
  708.   argc--; argv++;
  709.  
  710.   while (argc > 0 && **argv == '-')
  711.   {
  712.     if (argc > 0 && strnicmp(*argv, "-chunk", 2) == 0)
  713.     {
  714.       info = 0;
  715.       argc--; argv++;
  716.       continue;
  717.     }
  718.     if (argc > 0 && strnicmp(*argv, "-short", 2) == 0)
  719.     {
  720.       info = 1;
  721.       argc--; argv++;
  722.       continue;
  723.     }
  724.     if (argc > 0 && strnicmp(*argv, "-info", 2) == 0)
  725.     {
  726.       info = 2;
  727.       argc--; argv++;
  728.       continue;
  729.     }
  730.     if (argc > 0 && strnicmp(*argv, "-lyric", 2) == 0)
  731.     {
  732.       info = -1;
  733.       argc--; argv++;
  734.       continue;
  735.     }
  736.     if (argc > 0 && strnicmp(*argv, "-tact", 2) == 0)
  737.     {
  738.       tact = 1;
  739.       argc--; argv++;
  740.       continue;
  741.     }
  742.     fprintf(stderr, "invalid option %s\n", *argv);
  743.     argc--; argv++;
  744.     usage();
  745.   }
  746.   if (argc == 0)
  747.     usage();
  748.  
  749.   MidiPrint midi(*argv);
  750.   if (errno != 0)
  751.   {
  752.     perror(*argv);
  753.     return;
  754.   }
  755.   fprintf(stderr, "%s\n", *argv);
  756.   midi.info_ = info;
  757.   midi.marktact_ = tact;
  758.   if (info == 0)
  759.     midi.options_ = OPTION_NOEVENTS;
  760.   if (!midi.run())
  761.     fprintf(stderr, "midi error at %lx\n", midi.getpos());
  762. }
  763.  
  764.